﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using AngleSharp.Parser.Html;
using Common.Model;
using log4net;

namespace Spider.Spider
{
    public class ShQaSpider
    {

        public static string Nodata = "暂时没有问答内容";
        private static readonly ILog Log = LogManager.GetLogger(typeof(ShQaSpider));

        private static String GetQuestionHtml(int page)
        {

            var url = "http://sns.sseinfo.com/ajax/feeds.do?type=10&pageSize=100&lastid=-1&show=1&page=" + page;
            HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
            request.Method = WebRequestMethods.Http.Post;
            request.ContentType = "application/x-www-form-urlencoded";
            request.UserAgent =
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36";
            request.Referer = "http://sns.sseinfo.com/qa.do";
            request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8";

            HttpWebResponse response = (HttpWebResponse) request.GetResponse();
            Stream myResponseStream = response.GetResponseStream();
            StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"));
            string retString = myStreamReader.ReadToEnd();
            return retString;
        }

        private static String GetAnswerHtml(int page)
        {

            var url = "http://sns.sseinfo.com/ajax/feeds.do?type=11&pageSize=100&lastid=-1&show=1&page=" + page;
            HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
            request.Method = WebRequestMethods.Http.Post;
            request.ContentType = "application/x-www-form-urlencoded";
            request.UserAgent =
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36";
            request.Referer = "http://sns.sseinfo.com/qa.do";
            request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8";

            HttpWebResponse response = (HttpWebResponse) request.GetResponse();
            Stream myResponseStream = response.GetResponseStream();
            StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"));
            string retString = myStreamReader.ReadToEnd();
            return retString;
        }

        public static List<QAnswer> GetQuestion(DateTime startTime, DateTime endTime)
        {
            var page = 1;
            
            var qAnswers = new List<QAnswer>();
            var htmlParser = new HtmlParser();

            do
            {
                var qaHtml = GetQuestionHtml(page);
                var htmlDocument = htmlParser.Parse(qaHtml);
                var itemsQuerySelector = htmlDocument.QuerySelectorAll("div.m_feed_detail");
                var crawlingList = itemsQuerySelector.Select(m =>
                {
                    var textSelectors = m.QuerySelectorAll("div.m_feed_txt").ToList();
                    var querySelector = textSelectors[0];
                    var nameCodeHtml = querySelector.QuerySelector("a")?.InnerHtml.Trim()?.Replace(":","")?.Trim();
                    if (null == nameCodeHtml)
                    {
                        return null;
                    }
                    var nameCodeMatch = Regex.Match(nameCodeHtml, "(.*?)\\((.*?)\\)");
                    var code = nameCodeMatch.Groups[2].Value;
                    var name = nameCodeMatch.Groups[1].Value;
                    var qustionHtml = nameCodeHtml + ":" + querySelector.InnerHtml.Trim();
                    var match = Regex.Match(qustionHtml, "(<a.*?</a>).*?");
                    var question = qustionHtml.Replace(match.Groups[1].Value.Trim(),"").Trim();
                    
                    var timeSelectorAll = m.QuerySelectorAll("div.m_feed_from").ToList();

                    
                    var timeHtml = timeSelectorAll[0].QuerySelector("span").InnerHtml.Trim();

                    var time = GetDateTime(timeHtml);

                    var questionTime = time;

                    var id = CreateMd5Hash("SH." + code + "_" + question);
                    
                    return new QAnswer
                    {
                        Pid = id,
                        Question = question,
                        QuestionTime = questionTime,
                        Code = code,
                        From = "SH"
                    };
                }).Where(m=>null!=m).ToList();
                qAnswers.AddRange(crawlingList);
                page++;

                foreach (var qAnswer in crawlingList)
                {
                    Log.Info("crawlingQA question time = " + qAnswer.QuestionTime);
                }

                if (crawlingList.Any(m =>m.QuestionTime < startTime))
                {
                    break;
                }
                if (qaHtml.Contains(Nodata))
                {
                    break;
                }
            } while (true);
            
            return qAnswers;
        }

        public static List<QAnswer> GetAnswers(DateTime startTime, DateTime endTime)
        {
            var page = 1;

            var qAnswers = new List<QAnswer>();
            var htmlParser = new HtmlParser();

            do
            {
                var qaHtml = GetAnswerHtml(page);
                var htmlDocument = htmlParser.Parse(qaHtml);
                var itemsQuerySelector = htmlDocument.QuerySelectorAll("div.m_feed_item");

                var crawlingList = itemsQuerySelector.Select(m =>
                {
                    var questionSelector = m.QuerySelectorAll("div.m_feed_cnt")[0];
                   
                  
                    var nameCodeHtml = questionSelector.QuerySelector("a")?.InnerHtml.Trim()?.Replace(":", "")?.Trim();
                    if (null == nameCodeHtml)
                    {
                        return null;
                    }
                    var nameCodeMatch = Regex.Match(nameCodeHtml, "(.*?)\\((.*?)\\)");
                    var code = nameCodeMatch.Groups[2].Value;
                    var name = nameCodeMatch.Groups[1].Value;
                    var qustionHtml = nameCodeHtml + ":" + questionSelector.QuerySelector("div.m_feed_txt").InnerHtml.Trim();
                    var match = Regex.Match(qustionHtml, "(<a.*?</a>).*?");
                    var question = qustionHtml.Replace(match.Groups[1].Value.Trim(), "").Trim();

                    var answer = m.QuerySelectorAll("div.m_feed_cnt")[1].QuerySelector("div.m_feed_txt").InnerHtml.Replace("\t", "").Replace(" ", "").Replace("\n","").Trim();
                    var timeSelectorAll = m.QuerySelectorAll("div.m_feed_from").ToList();


                    var questionTimeHtml = timeSelectorAll[0].QuerySelector("span").InnerHtml.Trim();
                    var answerTimeHtml =
                        m.QuerySelectorAll("div.m_feed_from")[1].QuerySelector("span").InnerHtml.Trim();

                    var questionTime = GetDateTime(questionTimeHtml);
                    var answerTime = GetDateTime(answerTimeHtml);

                    var id = CreateMd5Hash("SH." + code + "_" + question);

                    return new QAnswer
                    {
                        Pid = id,
                        Question = question,
                        QuestionTime = questionTime,
                        Answer = answer,
                        AnswerTime =  answerTime,
                        Code = code,
                        From = "SH"
                    };
                }).Where(m => null != m).ToList();
                qAnswers.AddRange(crawlingList);
                page++;

                foreach (var qAnswer in crawlingList)
                {
                    Log.Info("crawlingQA answer time = " + qAnswer.AnswerTime + " question time = " + qAnswer.QuestionTime);
                }

                if (crawlingList.Any(m => m.AnswerTime < startTime))
                {
                    break;
                }
                if (qaHtml.Contains(Nodata))
                {
                    break;
                }
            } while (true);

            return qAnswers;
        }

        private static DateTime GetDateTime(String html)
        {
            var dateTime = DateTime.Now;
            if (html.Contains("秒前"))
            {
                var trim = html.Replace("秒前", "").Trim();
                dateTime = dateTime.AddSeconds(-int.Parse(trim));
            }
            else if(html.Contains("分钟"))
            {
                var trim = html.Replace("分钟前","").Trim();
                dateTime = dateTime.AddMinutes(-int.Parse(trim));
            }
            else if(html.Contains("小时前"))
            {
                var trim = html.Replace("小时前","").Trim();
                dateTime = dateTime.AddHours(-int.Parse(trim));
            }
            else if(html.Contains("昨天"))
            {
                var trim = html.Replace("昨天","").Trim();

                dateTime = DateTime.Today.AddDays(-1)
                    .AddHours(int.Parse(trim.Substring(0, 2)))
                    .AddMinutes(int.Parse(trim.Substring(3, 2)));
            }
            else if(!html.Contains("年")) 
            {
                var year = int.Parse(DateTime.Now.ToString("yyyy"));
                var month = int.Parse(DateTime.Now.ToString("MM"));
                var dateMonth = int.Parse(html.Substring(0, 2));
                if (month ==1 && dateMonth> month)
                {
                    dateTime = DateTime.ParseExact((year - 1) + html.Trim(),"yyyyMM月dd日 HH:mm",
                    System.Globalization.CultureInfo.CurrentCulture);
                }
                else
                {

                    dateTime = DateTime.ParseExact(html.Trim(), "MM月dd日 HH:mm",
                        System.Globalization.CultureInfo.CurrentCulture);
                }
            }
            else
            {
                dateTime = DateTime.ParseExact(html.Trim(), "yyyy年MM月dd日 HH:mm",
                    System.Globalization.CultureInfo.CurrentCulture);
                
            }
            return dateTime;
        }

        public static string CreateMd5Hash(string input)
        {
            // Use input string to calculate MD5 hash
            MD5 md5 = System.Security.Cryptography.MD5.Create();
            byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
            byte[] hashBytes = md5.ComputeHash(inputBytes);

            // Convert the byte array to hexadecimal string
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < hashBytes.Length; i++)
            {
                sb.Append(hashBytes[i].ToString("X2"));
                // To force the hex string to lower-case letters instead of
                // upper-case, use he following line instead:
                // sb.Append(hashBytes[i].ToString("x2")); 
            }
            return sb.ToString();
        }

    }
}